import qs from 'qs';
import { notNilEmpty } from 'qx-util';
import { clone } from 'ramda';
import type { IContext, IParam } from '../interface';
import type { ControlVOBase } from '../modules';
import { PluralizeRule } from './pluralize-rule';
import { VerifyUtil } from './verify-util';

const pluralizeRule = new PluralizeRule();

/**
 * @description 克隆方法
 * @export
 * @param {Record<any, any>} data
 * @return {*}  {Record<any, any>}
 */
export function deepCopy(data: Record<any, any>): Record<any, any> {
	return clone(data);
}

/**
 * 对象是否有属性
 * @description 适配使用get set的Object对象
 * @export
 * @param {*} obj 对象
 * @param {string} key 属性标识
 * @return {*}  {boolean}
 */
export function hasKey(obj: any, key: string): boolean {
	return obj.hasOwnProperty(key) || key in obj;
}

/**
 * 名称格式化
 *
 * @export
 * @param {string} name 名称
 * @return {*}  {string}
 */
export function srfFilePath2(name: string): string {
	if (!name || (name && Object.is(name, ''))) {
		console.error('名称异常');
		return '';
	}
	name = name.replace(/[_]/g, '-');
	let state = 0;
	let _str = '';
	const uPattern = /^[A-Z]{1}$/;

	const str1 = name.substring(0, 1);
	const str2 = name.substring(1);
	state = uPattern.test(str1) ? 1 : 0;
	_str = `${_str}${str1.toLowerCase()}`;

	for (const chr of str2) {
		if (uPattern.test(chr)) {
			if (state === 1) {
				_str = `${_str}${chr.toLowerCase()}`;
			} else {
				_str = `${_str}-${chr.toLowerCase()}`;
			}
			state = 1;
		} else {
			_str = `${_str}${chr.toLowerCase()}`;
			state = 0;
		}
	}
	_str = _str.replace(/---/g, '-').replace(/--/g, '-');

	return _str;
}

/**
 * 创建UUID
 *
 * @export
 * @return {*}  {string}
 */
export function createUUID(): string {
	function s4() {
		return Math.floor((1 + Math.random()) * 0x10000)
			.toString(16)
			.substring(1);
	}
	return (
		s4() +
		s4() +
		'-' +
		s4() +
		'-' +
		s4() +
		'-' +
		s4() +
		'-' +
		s4() +
		s4() +
		s4()
	);
}

/**
 * 判断对象是否为空，避免发生数值0误判
 *
 * @param obj
 */
export function isExist(obj: any): boolean {
	return obj !== undefined && obj !== null;
}

/**
 * 字符串不为空并且对象存在
 *
 * @param str
 */
export function isExistAndNotEmpty(str: string | undefined | null): boolean {
	return isExist(str) && !isEmpty(str);
}

/**
 * @description 是否拥有某个方法
 * @param {*} arg 校验对象
 * @param fnName 方法名
 * @return {*}
 */
export function hasFunction(arg: any, fnName: string): boolean {
	return arg[fnName] && arg[fnName] instanceof Function;
}

/**
 * 判断指定值是否为空
 * @param value
 * @returns
 */
export function isEmpty(value: any): boolean {
	return (
		isUndefined(value) ||
		Object.is(value, '') ||
		value === null ||
		value !== value
	);
}

/**
 * 判断是否为空对象
 *
 * @export
 * @param {*} arg
 * @return {*}  {boolean}
 */
export function isEmptyObj(arg: any): boolean {
	if (!(arg instanceof Object)) {
		return false;
	}
	return Object.is(JSON.stringify(arg), '{}');
}

/**
 * 判断指定值是否为未定义
 * @param value
 * @returns
 */
export function isUndefined(value: any): boolean {
	return typeof value === 'undefined';
}

/**
 * 判断指定值是否存在
 * @param arg
 * @returns
 */
export function notEmpty(arg: any): boolean {
	return isExist(arg) && arg != '';
}

/**
 * @description 获取当前数据值类型
 * @export
 * @param {*} obj 当前数据
 * @return {*}  {string}
 */
export function typeOf(obj: any): string {
	const toString = Object.prototype.toString;
	const map: any = {
		'[object Boolean]': 'boolean',
		'[object Number]': 'number',
		'[object String]': 'string',
		'[object Function]': 'function',
		'[object Array]': 'array',
		'[object Date]': 'date',
		'[object RegExp]': 'regExp',
		'[object Undefined]': 'undefined',
		'[object Null]': 'null',
		'[object Object]': 'object',
	};
	return map[toString.call(obj)];
}

/**
 * 日期格式化
 *
 * @export
 * @param {*} date 日期对象
 * @param {string} [fmt='YYYY-MM-DD HH:mm:ss'] 格式化
 * @return {*}  {string}
 */
export function dateFormat(date: any, fmt = 'YYYY-MM-DD HH:mm:ss'): string {
	let ret;
	const opt: any = {
		'Y+': date.getFullYear().toString(), // 年
		'M+': (date.getMonth() + 1).toString(), // 月
		'd+': date.getDate().toString(), // 日
		'D+': date.getDate().toString(), // 日
		'H+': date.getHours().toString(), // 时
		'h+': date.getHours().toString(), // 时
		'm+': date.getMinutes().toString(), // 分
		's+': date.getSeconds().toString(), // 秒
		'S+': date.getSeconds().toString(),
		// 有其他格式化字符需求可以继续添加，必须转化成字符串
	};
	for (const k in opt) {
		ret = new RegExp('(' + k + ')').exec(fmt);
		if (ret) {
			fmt = fmt.replace(
				ret[1],
				ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0')
			);
		}
	}
	return fmt;
}

/**
 * 校验动态逻辑
 *
 * @export
 * @param {IParam} data 数据
 * @param {IParam} logic 动态逻辑
 * @return {*}  {boolean}
 */
export function verifyDynamicLogic(data: IParam, logic: IParam): boolean {
	if (logic.logicType == 'GROUP' && logic.childLogics?.length > 0) {
		let result = true;
		if (logic.groupOP == 'AND') {
			const falseItem = logic.childLogics.find((childLogic: IParam) => {
				return !verifyDynamicLogic(data, childLogic);
			});
			result = falseItem ? false : true;
		} else if (logic.groupOP == 'OR') {
			const trueItem = logic.childLogics.find((childLogic: IParam) => {
				return verifyDynamicLogic(data, childLogic);
			});
			result = trueItem ? true : false;
		}
		// 是否取反
		return logic.notMode ? !result : result;
	} else if (logic.logicType == 'SINGLE') {
		return VerifyUtil.testCond(data[logic.dEFDName], logic.condOP, logic.value);
	}
	return false;
}

/**
 * 校验界面逻辑连接条件
 *
 * @export
 * @param {IParam} linkCond
 * @return {*}  {boolean}
 */
export function verifyNodeLinkCond(linkCond: IParam): boolean {
	if (linkCond.logicType == 'GROUP' && linkCond.childLogics?.length > 0) {
		let result = true;
		if (linkCond.groupOP == 'AND') {
			const falseItem = linkCond.childLogics.find((childLogic: IParam) => {
				return !verifyNodeLinkCond(childLogic);
			});
			result = falseItem ? false : true;
		} else if (linkCond.groupOP == 'OR') {
			const trueItem = linkCond.childLogics.find((childLogic: IParam) => {
				return verifyNodeLinkCond(childLogic);
			});
			result = trueItem ? true : false;
		}
		// 是否取反
		return linkCond.notMode ? !result : result;
	} else if (linkCond.logicType == 'SINGLE') {
		return VerifyUtil.testCond(
			linkCond.verifyValue,
			linkCond.condOP,
			linkCond.value
		);
	}
	return false;
}

const map = new WeakMap();

/**
 * 防抖
 *
 * @param {any} fun 函数
 * @param {any} params 参数
 * @param {number} wait 延迟时间，默认300
 * @static
 * @memberof Util
 */
export const debounce: Function = (
	fun: any,
	params: any,
	context: any,
	wait = 300
) => {
	if (typeof fun === 'function') {
		if (map.has(fun)) {
			const num = map.get(fun);
			clearTimeout(num);
		}
		map.set(
			fun,
			setTimeout(() => {
				map.delete(fun);
				fun.apply(context, params);
			}, wait)
		);
	}
};

/**
 * 节流
 *
 * @param {any} fun 函数
 * @param {any} params 参数
 * @param {any} context 方法上下文
 * @param {number} delay 延迟时间，默认300
 * @static
 * @memberof Util
 */
export const throttle: Function = (
	fun: any,
	params: any[],
	context: any,
	delay = 300
) => {
	const now: any = Date.now();
	if (!fun.last || now - fun.last >= delay) {
		if (typeof fun === 'function') {
			return fun.apply(context, params);
		}
		fun.last = now;
	}
};

/**
 * 根据标识获取sessionStorage数据
 *
 * @export
 * @param {string} key 标识
 * @return {*}
 */
export function getSessionStorage(key: string) {
	if (!key) {
		return null;
	}
	const value = sessionStorage.getItem(key);
	if (value) {
		return JSON.parse(value);
	} else {
		return value;
	}
}

/**
 * 设置sessionStorage数据
 *
 * @export
 * @param {string} key
 * @param {*} value
 * @return {*}
 */
export function setSessionStorage(key: string, value: any) {
	if (!value) {
		return;
	}
	sessionStorage.setItem(key, JSON.stringify(value));
}

/**
 * @description 计算单词复数
 * @export
 * @param {string} word
 * @return {*}
 */
export function srfpluralize(word: string) {
	const wordStr = word.trim().toLowerCase();
	if (wordStr.length == 0) {
		return wordStr;
	}
	if (pluralizeRule.isUncountable(wordStr)) {
		return wordStr;
	}
	const newWordStr = pluralizeRule.irregularChange(wordStr);
	if (newWordStr) {
		return newWordStr;
	} else {
		return pluralizeRule.ruleChange(wordStr);
	}
}

/**
 * 深度合并对象
 *
 * @param FirstOBJ 目标对象
 * @param SecondOBJ 原对象
 * @returns {Object}
 * @memberof Util
 */
export function deepObjectMerge(FirstOBJ: any, SecondOBJ: any) {
	for (const key in SecondOBJ) {
		FirstOBJ[key] =
			FirstOBJ[key] && FirstOBJ[key].toString() === '[object Object]'
				? deepObjectMerge(FirstOBJ[key], SecondOBJ[key])
				: (FirstOBJ[key] = SecondOBJ[key]);
	}
	return FirstOBJ;
}

/**
 * 计算导航数据
 *
 * @export
 * @param {*} data 表单数据
 * @param {*} parentContext 上下文
 * @param {*} parentParam 视图参数
 * @param {*} params 额外参数
 * @return {*}  {*}
 */
export function computedNavData(
	data: any,
	parentContext: any,
	parentParam: any,
	params: any
): any {
	const _data: any = {};
	if (params && Object.keys(params).length > 0) {
		Object.keys(params).forEach((name: string) => {
			if (!name) {
				return;
			}
			let value: string | null = params[name];
			if (
				value &&
				value.toString().startsWith('%') &&
				value.toString().endsWith('%')
			) {
				const key = value.substring(1, value.length - 1).toLowerCase();
				if (data && data.hasOwnProperty(key)) {
					value = data[key];
				} else if (parentContext && parentContext[key]) {
					value = parentContext[key];
				} else if (parentParam && parentParam[key]) {
					value = parentParam[key];
				} else {
					value = null;
				}
			}
			Object.assign(_data, { [name.toLowerCase()]: value });
		});
	}
	return _data;
}

/**
 * 获取路由参数(http://127.0.0.1:8080/?aaa=bbb&ccc=ddd#/index/views/viewtypeindexview)
 * 解析?和#之间的参数作为应用级参数
 *
 * @export
 * @param {string} path 路径
 * @return {*}
 */
export function getRouteParams(path: string) {
	const returnParams = {};
	if (path.indexOf('?') !== -1 && path.indexOf('#') !== -1) {
		const tempPath: string = path.slice(
			path.indexOf('?') + 1,
			path.indexOf('#')
		);
		const pathArray: Array<string> = tempPath.split('&');
		if (pathArray && pathArray.length > 0) {
			pathArray.forEach((item: any) => {
				if (item && item.indexOf('=') !== -1) {
					Object.assign(returnParams, qs.parse(item));
				}
			});
		}
	}
	return returnParams;
}

/**
 * @description 填充字符串中的数据
 * @export
 * @param {string} str 路径
 * @param {IContext} context 上下文
 * @param {IParam} viewParams 视图参数
 * @return {*}  {string}
 */
export function fillStrData(
	str: string,
	context: IContext,
	viewParams: IParam
): string {
	if (notNilEmpty(str)) {
		if (notNilEmpty(context)) {
			const contextReg = /\$\{context.[a-zA-Z_$][a-zA-Z0-9_$]{1,}\}/g;
			const strArr = str.match(contextReg);
			strArr?.forEach((_key) => {
				const key = _key.slice(10, _key.length - 1);
				str = str.replace(`\${context.${key}}`, context[key] || '');
			});
		}
		if (notNilEmpty(viewParams)) {
			const dataReg = /\$\{data.[a-zA-Z_$][a-zA-Z0-9_$]{1,}\}/g;
			const strArr = str.match(dataReg);
			strArr?.forEach((_key) => {
				const key = _key.slice(7, _key.length - 1);
				str = str.replace(`\${data.${key}}`, viewParams[key] || '');
			});
		}
	}
	return str;
}

/**
 * 格式化数据
 *
 * @private
 * @static
 * @param {*} actionTarget
 * @param {*} args
 * @param parentContext
 * @param parentParams
 * @param {*} _params
 * @returns {*}
 */
export function formatActionData(
	actionTarget: string,
	args: IParam[],
	parentContext: IContext,
	parentParams: IParam,
	_params: IParam
): IParam {
	const _data: IParam = {};
	if (
		Object.is(actionTarget, 'SINGLEKEY') ||
		Object.is(actionTarget, 'NONE') ||
		Object.is(actionTarget, 'SINGLEDATA')
	) {
		let arg: IParam = {};
		if (args && args.length > 0) {
			[arg] = args;
		}
		Object.keys(_params).forEach((name: string) => {
			let hasProperty = true;
			if (!name) {
				return;
			}
			let value: string | null = _params[name];
			if (
				value &&
				typeof value === 'string' &&
				value.startsWith('%') &&
				value.endsWith('%')
			) {
				const key = value.substring(1, value.length - 1);
				if (arg && hasKey(arg, key)) {
					value = arg[key] !== null && arg[key] !== undefined ? arg[key] : null;
				} else if (parentContext && hasKey(parentContext, key)) {
					value =
						parentContext[key] !== null && parentContext[key] !== undefined
							? parentContext[key]
							: null;
				} else if (parentParams && hasKey(parentParams, key)) {
					value =
						parentParams[key] !== null && parentParams[key] !== undefined
							? parentParams[key]
							: null;
				} else {
					hasProperty = false;
				}
			}
			if (hasProperty) {
				Object.assign(_data, { [name.toLowerCase()]: value });
			}
		});
	} else if (Object.is(actionTarget, 'MULTIKEY')) {
		Object.keys(_params).forEach((name: string) => {
			let noPropertyNum = 0;
			if (!name) {
				return;
			}
			let value: string | null = _params[name];
			const values: any[] = [];
			if (
				value &&
				typeof value === 'string' &&
				value.startsWith('%') &&
				value.endsWith('%')
			) {
				const key = value.substring(1, value.length - 1);
				args.forEach((arg: any) => {
					if (arg && hasKey(arg, key)) {
						value =
							arg[key] !== null && arg[key] !== undefined ? arg[key] : null;
					} else if (parentContext && hasKey(parentContext, key)) {
						value =
							parentContext[key] !== null && parentContext[key] !== undefined
								? parentContext[key]
								: null;
					} else if (parentParams && hasKey(parentParams, key)) {
						value =
							parentParams[key] !== null && parentParams[key] !== undefined
								? parentParams[key]
								: null;
					} else {
						value = null;
						noPropertyNum++;
					}
					values.push(value);
				});
			}
			if (values.length !== noPropertyNum) {
				Object.assign(_data, {
					[name.toLowerCase()]: values.length > 0 ? values.join(',') : value,
				});
			}
		});
	}
	return _data;
}

/**
 * @description 获取当前国际化
 * @return {*}  {string}
 * @memberof EditorBase
 */
export function getLocal(): string {
	//todo
	return 'zh_CN';
}

/**
 * @description 首字母大写
 * @return {*}  {string}
 */
export function UpperFirstLetter(str: string) {
	const str1 = str.substring(0, 1).toUpperCase();
	const str2 = str.substring(1);
	return str1 + str2;
}

/**
 * 获取盒子大小（宽高模式针对面板项，按钮等项模型是控制的布局内容的宽高）
 * @param mode 模式 "WIDTH" | "HEIGHT"
 * @param style 样式 "FULL"(全部宽度) | "PX"（像素） | "PERCENTAGE"（百分比）
 * @param value
 * @returns
 */
export function getBoxSize(
	mode: 'WIDTH' | 'HEIGHT',
	style: string,
	value: number
) {
	if (!mode) {
		return {};
	}
	if (!style) {
		style = 'PX';
	}
	if (style === 'FULL') {
		return { [mode.toLowerCase()]: '100%' };
	} else {
		if (!value) {
			return {};
		} else if (style === 'PERCENTAGE') {
			return { [mode.toLowerCase()]: `${value}%` };
		} else {
			return { [mode.toLowerCase()]: `${value}px` };
		}
	}
}

/**
 * 获取VO原始数据
 *
 * @export
 * @param {(ControlVOBase | ControlVOBase[] | IParam | IParam[])} data
 * @return {*}  {(IParam | IParam[])}
 */
export function transformRawData(
	data: ControlVOBase | ControlVOBase[] | IParam | IParam[]
): IParam | IParam[] {
	if (!data || data.length === 0) {
		return data;
	}
	const handle = (item: ControlVOBase | IParam): IParam => {
		//  有此两项属性表明该对象是VO对象
		if (item.$ownKeys && item.$DO) {
			return item.toObject();
		}
		return item;
	};
	if (Object.prototype.toString.call(data) === '[object Array]') {
		const items: IParam[] = [];
		data.forEach((item: ControlVOBase | IParam) => {
			items.push(handle(item));
		});
		return items;
	}
	if (Object.prototype.toString.call(data) === '[object Object]') {
		return handle(data);
	}
	return data;
}

/**
 * VO转换成DO数据
 *
 * @export
 * @param {(ControlVOBase | ControlVOBase[])} data
 * @return {*}  {(IParam | IParam[])}
 */
export function transformDoData<T = IParam | IParam[]>(
	data: ControlVOBase | ControlVOBase[] | IParam | IParam[]
): T {
	if (!data || data.length === 0) {
		return data as T;
	}
	const handle = (item: ControlVOBase | IParam): IParam => {
		//  有此两项属性表明该对象是VO对象
		if (
			item.$ownKeys &&
			item.$DO &&
			item.getDo &&
			item.getDo instanceof Function
		) {
			return item.getDo();
		}
		if (item.$DO) {
			delete item.$DO;
		}
		if (item.$ownKeys) {
			delete item.$ownKeys;
		}
		return item;
	};
	if (Object.prototype.toString.call(data) === '[object Array]') {
		const items: IParam[] = [];
		data.forEach((item: ControlVOBase | IParam) => {
			items.push(handle(item));
		});
		return items as T;
	}
	if (Object.prototype.toString.call(data) === '[object Object]') {
		return handle(data) as T;
	}
	return data as T;
}

/**
 * 格式化URL字符串（适配老配置）
 *
 * @export
 * @param {string} url
 * @param {IContext} [context={}]
 * @param {IParam} [viewParams={}]
 * @param {IParam} [data={}]
 * @return {*}  {string}
 */
export function formatUrlString(
	url: string,
	context: IContext = {},
	viewParams: IParam = {},
	data: IParam = {}
): string {
	if (!url || url === '') {
		return url;
	}
	const reg =
		/\$\{context.[a-zA-Z_]*[a-zA-Z0-9-_]*}|\$\{viewParams.[a-zA-Z_]*[a-zA-Z0-9-_]*}|\$\{viewparams.[a-zA-Z_]*[a-zA-Z0-9-_]*}|\$\{data.[a-zA-Z_]*[a-zA-Z0-9-_]*}/g;
	const results = url.match(reg);
	if (results && results.length > 0) {
		results.forEach((result: string) => {
			const keys = result.split('.');
			if (keys && keys.length === 2) {
				const key = keys[0].replace('${', '').toLowerCase();
				const value = keys[1].replace('}', '');
				if (key === 'context') {
					url = url.replace(result, context[value]);
				} else if (key === 'viewparams') {
					url = url.replace(result, viewParams[value]);
				} else if (key === 'data') {
					url = url.replace(result, data[value]);
				}
			}
		});
	}
	return url;
}

/**
 * 合并视图参数
 *
 * @export
 * @param {IParam} data 业务数据
 * @param {IParam} [viewParams={}] 视图参数
 * @return {*}
 */
export function mergeViewParams(data: IParam, viewParams: IParam = {}) {
	if (
		!data ||
		Object.keys(data).length === 0 ||
		!viewParams ||
		Object.keys(viewParams).length === 0
	) {
		return;
	}
	Object.keys(viewParams).forEach((key: string) => {
		if (!data.hasOwnProperty(key)) {
			Object.assign(data, { [key]: viewParams[key] });
		}
	});
}

/**
 * @description 处理层级代码表
 * @export
 * @param {IParam[]} items
 * @param {IParam[]} result
 */
export function handleLevelCodeList(items: IParam[]) {
	if (items && items.length > 0) {
		const hasChildren = items.some((item: IParam) => {
			return item.pvalue;
		});
		if (hasChildren) {
			let list: IParam[] = [];
			items.forEach((codeItem: IParam) => {
				if (!codeItem.pvalue) {
					let valueField: string = codeItem.value;
					setChildCodeItems(valueField, items, codeItem);
					list.push(codeItem);
				}
			});
			return list;
		} else {
			return items;
		}
	}
}

/**
 * @description 设置子项代码表
 * @param {string} pValue
 * @param {Array<any>} result
 * @param {*} codeItem
 */
function setChildCodeItems(pValue: string, result: Array<any>, codeItem: any) {
	result.forEach((item: any) => {
		if (item.pvalue == pValue) {
			let valueField: string = item.value;
			setChildCodeItems(valueField, result, item);
			if (!codeItem.children) {
				codeItem.children = [];
			}
			codeItem.children.push(item);
		}
	});
}

/**
 * 格式化视图关系参数
 *
 * @export
 * @param {*} context 应用上下文数据
 * @param {any[][]} appDERSPaths 关系路径数据
 * @return {*}  {*}
 */
export function formatAppDERSPath(
	context: any,
	appDERSPaths: any[] | undefined
): any {
	if (!appDERSPaths || appDERSPaths.length === 0) {
		return [];
	}
	let counter: number = 0;
	for (const appDERSPath of appDERSPaths) {
		let tempData: any = { isInclude: true, data: [] };
		for (const singleAppDERSPath of appDERSPath) {
			tempData.isInclude =
				context[singleAppDERSPath.parameterName.toLowerCase()] &&
				tempData.isInclude;
			tempData.data.push(singleAppDERSPath);
		}
		counter++;
		if (tempData.isInclude) {
			return tempData.data;
		} else {
			if (counter === appDERSPaths.length) {
				return [];
			}
		}
	}
}
